package main

import "fmt"

type LinearContainer interface {
	Push(data any)
	Pop() any
}

type Queue struct {
	data []any
}

func (q *Queue) Push(data any) {
	q.data = append(q.data, data)
}

func (q *Queue) Pop() any {
	if len(q.data) == 0 {
		return nil
	}
	data := q.data[0]
	q.data = q.data[1:]
	return data
}

type Stack struct {
	data []any
}

func (s *Stack) Push(data any) {
	s.data = append(s.data, data)
}

func (s *Stack) Pop() any {
	l := len(s.data)
	if l == 0 {
		return nil
	}
	data := s.data[l-1]
	s.data = s.data[:l-1]
	return data
}

type LinearContainerFactory struct{}

func (f *LinearContainerFactory) Create(name string) LinearContainer {
	switch name {
	case "queue":
		return &Queue{}
	case "stack":
		return &Stack{}
	default:
		return nil
	}
}

func main() {
	factory := &LinearContainerFactory{}
	queue := factory.Create("queue")
	stack := factory.Create("stack")
	for i := 0; i < 3; i++ {
		queue.Push(i)
		stack.Push(i)
	}
	for data := queue.Pop(); data != nil; data = queue.Pop() {
		fmt.Println("Queue pop ", data)
	}
	for data := stack.Pop(); data != nil; data = stack.Pop() {
		fmt.Println("Stack pop ", data)
	}
}
